home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / WASTE 1.2 / WASTE Tabs / WETabHooks.c next >
Text File  |  1996-05-19  |  7KB  |  252 lines

  1. /*
  2.  *    WETabHooks.c
  3.  *
  4.  *    Hooks for adding tab support to WASTE.
  5.  *    
  6.  *    Original code by Mark Alldritt
  7.  *    Line breaking code by Dan Crevier
  8.  *    Support for horizontal scrolling by Bert Seltzer
  9.  *    Maintenance by John C. Daub
  10.  *    Further modifications by Marco Piovanelli
  11.  *
  12.  */
  13.  
  14. #include "WETabHooks.h"
  15.  
  16. #ifndef kTabWidth
  17. #define    kTabWidth    32
  18. #endif
  19.  
  20. /*
  21.     If kTabWidth is a power of two, we can exploit the fact that
  22.         (x % kTabWidth) == (x & (kTabWidth - 1))
  23.     and replace those expensive modulus (%) operators with much
  24.     cheaper ANDs.  (From a suggestion by Mark Valence.)
  25. */
  26.  
  27. #define IS_POWER_OF_TWO(x)        (((x) & ((x) - 1)) == 0)
  28.  
  29. #if IS_POWER_OF_TWO(kTabWidth)
  30.     /* inline short MOD(short x) { return (x & (kTabWidth - 1)); } */
  31.     #define MOD(x)                (((short) (x)) & (kTabWidth - 1))
  32. #else
  33.     /* inline short MOD(short x) { return (x % kTabWidth); } */
  34.     #define MOD(x)                (((short) (x)) % kTabWidth)
  35. #endif
  36.  
  37. /* inline short FIXROUND(Fixed f) { return ((f + 0x00008000) >> 16); } */
  38. #define FIXROUND(f)        ((short) (((f) + 0x00008000) >> 16))
  39.  
  40. #ifndef BSL
  41. #define BSL( A, B )            (((long) (A)) << (B))
  42. #endif
  43.  
  44. static const Point kOneToOneScaling = { 1, 1 } ;
  45.  
  46. pascal void _WETabDrawText(Ptr pText, long textLength, Fixed slop,
  47.                 JustStyleCode styleRunPosition, WEReference we)
  48. {
  49. #pragma unused(slop, styleRunPosition)
  50.  
  51.     LongRect destRect;
  52.     long beginChar = 0;
  53.     long ii;
  54.     short tabWidth;
  55.     short destLeft;
  56.     Point penPos;
  57.     
  58.     WEGetDestRect(&destRect, we);
  59.     destLeft = (short) destRect.left;
  60.     
  61.     for ( ii = 0; ii < textLength; ii++ )
  62.     {
  63.         if (pText[ii] == '\t')
  64.         {
  65.             DrawText(pText, beginChar, ii - beginChar);
  66.  
  67.             /* advance the pen to the next tab stop */
  68.             GetPen(&penPos);
  69.             tabWidth = kTabWidth - MOD(penPos.h - destLeft);
  70.             MoveTo(penPos.h + tabWidth, penPos.v);
  71.             beginChar = ii + 1;
  72.         }
  73.     }    /* for */
  74.  
  75.     DrawText(pText, beginChar, textLength - beginChar);
  76. }
  77.  
  78. pascal long _WETabPixelToChar(Ptr pText, long textLength, Fixed slop,
  79.                 Fixed *width, char *edge, JustStyleCode styleRunPosition,
  80.                 Fixed hPos, WEReference we)
  81. {
  82. #pragma unused(we)
  83.  
  84.     long beginChar = 0;
  85.     long offset = 0;
  86.     long ii;
  87.     Fixed lastWidth;
  88.     Fixed tabWidth;
  89.     
  90.     /* loop through every character in the segment looking for tabs */
  91.     for ( ii = 0; ii < textLength; ii++ )
  92.     {
  93.         /* exit now if width has gone negative */
  94.         /* (i.e., if we have found which glyph was hit) */
  95.         if (*width <= 0)
  96.             break;
  97.  
  98.         /* tab found? */
  99.         if (pText[ii] == '\t')
  100.         {
  101.             /* calculate the width of the sub-segment preceding the tab */
  102.             lastWidth = *width;
  103.             offset += PixelToChar(pText + beginChar, ii - beginChar, slop,
  104.                     lastWidth, (unsigned char *) edge, width, styleRunPosition,
  105.                     kOneToOneScaling, kOneToOneScaling);
  106.             beginChar = ii + 1;
  107.  
  108.             /* hit point past sub-segment? */
  109.             if (*width >= 0)
  110.             {
  111.                 /* increment hPos by width of sub-segment preceding the tab */
  112.                 hPos += (lastWidth - *width);
  113.                 
  114.                 /* calculate the width of the tab "glyph" (as a Fixed value) */
  115.                 tabWidth = BSL(kTabWidth - MOD(FIXROUND(hPos)), 16);
  116.                 
  117.                 /* increment hPos by width of tab character */
  118.                 hPos += tabWidth;
  119.                 
  120.                 /* hit point within tab glyph? */
  121.                 if (*width < tabWidth)
  122.                 {
  123.                     /* yes: determine which half of tab glyph was hit */
  124.                     if (*width > (tabWidth >> 1))
  125.                     {
  126.                         *edge = kTrailingEdge;    /* second (trailing) edge of tab */
  127.                         offset++;
  128.                     }
  129.                     else
  130.                         *edge = kLeadingEdge;    /* first (leading) edge of tab */
  131.                     
  132.                     /* returning -1 (as Fixed) in width means we're finished */
  133.                     *width = 0xFFFF0000;
  134.                 }
  135.                 else {
  136.                     /* hit point is past tab: keep looping */
  137.                     offset++;
  138.                     *width -= tabWidth;
  139.                 }
  140.             } /* if (*width >= 0) */
  141.         } /* if tab found */
  142.     } /* for */
  143.     
  144.     /* no more tabs in this segment: process the last sub-segment */
  145.     if (*width >= 0)
  146.     {
  147.         lastWidth = *width;
  148.         offset += PixelToChar(pText + beginChar, textLength - beginChar, slop,
  149.                     lastWidth, (unsigned char *) edge, width, styleRunPosition,
  150.                     kOneToOneScaling, kOneToOneScaling);
  151.     }
  152.     
  153.     /* round width to nearest integer value */
  154.     /* this is supposed to fix an incompatibility with the WorldScript Power Adapter */
  155.     *width = (*width + 0x00008000) & 0xFFFF0000;
  156.     
  157.     return offset;
  158. }
  159.  
  160. pascal short _WETabCharToPixel(Ptr pText, long textLength, Fixed slop,
  161.                 long offset, short direction, JustStyleCode styleRunPosition,
  162.                 long hPos, WEReference we)
  163. {
  164. #pragma unused(slop, direction, styleRunPosition)
  165.  
  166.     LongRect destRect;
  167.     long beginChar = 0;
  168.     long ii;
  169.     short width;
  170.     short destLeft;
  171.     short totalWidth = 0;
  172.  
  173.     WEGetDestRect(&destRect, we);
  174.     destLeft = (short) destRect.left;
  175.  
  176.     /* measure text up to offset, if offset is within this segment */
  177.     if (offset < textLength)
  178.         textLength = offset;
  179.     
  180.     for ( ii = 0; ii < textLength; ii++ )
  181.     {
  182.         if (pText[ii] == '\t')
  183.         {
  184.             /* calculate the pixel width of the subsegment preceding the tab */
  185.             width = TextWidth(pText, beginChar, ii - beginChar);
  186.             totalWidth += width;
  187.             hPos += width;
  188.             
  189.             /* calculate tab width */
  190.             width = kTabWidth - MOD(hPos - destLeft);
  191.             totalWidth += width;
  192.             hPos += width;
  193.             
  194.             /* go to next subsegment */
  195.             beginChar = ii + 1;
  196.         }
  197.     } /* for */
  198.     
  199.     /* calculate width of remaining characters */
  200.     width = TextWidth(pText, beginChar, textLength - beginChar);
  201.     totalWidth += width;
  202.     
  203.     return totalWidth;
  204. }
  205.  
  206. pascal StyledLineBreakCode _WETabLineBreak(Ptr pText, long textLength,
  207.             long textStart, long textEnd, Fixed *textWidth,
  208.             long *textOffset, WEReference we)
  209. {
  210.     LongRect destRect;
  211.     long beginChar = textStart;
  212.     long ii;
  213.     Fixed tabWidth;
  214.     short destWidth;
  215.     StyledLineBreakCode breakCode = smBreakOverflow;
  216.     
  217.     WEGetDestRect(&destRect, we);
  218.     destWidth = (short) (destRect.right - destRect.left);
  219.     
  220.     for ( ii = textStart; ii < textEnd; ii++ )
  221.     {
  222.         if (pText[ii] == '\t')
  223.         {
  224.             /* do previous "segment" */
  225.             breakCode = StyledLineBreak(pText, textLength, beginChar,
  226.                             ii, 0, textWidth, textOffset);
  227.             if ((breakCode != smBreakOverflow) || (ii >= textLength))
  228.                 break;
  229.             beginChar = ii + 1;
  230.             
  231.             /* calculate tab width (as a Fixed value) */
  232.             tabWidth = BSL(kTabWidth - MOD(destWidth - FIXROUND(*textWidth)), 16);
  233.             
  234.             /* if tabWidth > pixelWidth we break in tab */
  235.             /* don't move tab to next line */
  236.             if (tabWidth > *textWidth)
  237.             {
  238.                 breakCode = smBreakWord;
  239.                 *textOffset = ii + 1;
  240.                 break;
  241.             }
  242.             else
  243.                 *textWidth -= tabWidth;
  244.         }
  245.     } /* for */
  246.  
  247.     /* do last sub-segment */
  248.     if ((ii - beginChar >= 0) && (breakCode == smBreakOverflow))
  249.         breakCode = StyledLineBreak(pText, textLength, beginChar, ii, 0, textWidth, textOffset);
  250.     
  251.     return breakCode;
  252. }